package netTracker.network;
import java.awt.event.*;

import javax.swing.*;

@SuppressWarnings("serial")
/**
 * Test GUI for the Leader Election algorithm.
 * Note: Name Server must be running.
 * 
 * @author David Cummings
 *
 */
public class LeaderElectionGUI extends JFrame implements ActionListener{
	
	final static String HOSTNAME = "localhost";
	final static int STARTPORT = 23480;
	
	/** Total number of nodes: */
	static int numNodes;
	/** Total number of elections to hold: */
	static int numElections;
	static int nodeToStartElection = -1;
	/** Total number of messages sent: */
	public static int numMessages = 0;
	
	Node[] nodes;
	JTextArea nodesText;
	JTextArea electionText;
	boolean electing=false;
	boolean created=false;
	
	public LeaderElectionGUI(){
		setTitle("Leader Election");				// Set title.
		setDefaultCloseOperation(EXIT_ON_CLOSE);	// Guarantee program exits.
		
		JButton joinNetwork = new JButton("Join Network");
		joinNetwork.addActionListener(this);
		
		JButton startElection = new JButton("Start Election");
		startElection.addActionListener(this);
		
		JButton printTopology = new JButton("Print Topology");
		printTopology.addActionListener(this);
		
		JLabel nodesLabel = new JLabel("Nodes: ");
		nodesText = new JTextArea("4",1,6);
		JLabel electionLabel = new JLabel("Simultaneous elections: ");
		electionText = new JTextArea("1",1,6);
				
		JPanel myPanel = new JPanel();
		myPanel.add(joinNetwork);
		myPanel.add(nodesLabel);
		myPanel.add(nodesText);
		myPanel.add(electionLabel);
		myPanel.add(electionText);
		myPanel.add(startElection);
		myPanel.add(printTopology);
		add(myPanel);		
		pack();
		setLocationRelativeTo(null);	// center frame
		setVisible(true);
	}
	
	public void createNodes(){
		try{
			numNodes = Integer.parseInt(nodesText.getText());
			numElections = Integer.parseInt(electionText.getText());
		}catch(NumberFormatException e){
			System.err.println("Invalid numbers. Using default: 4 nodes, 1 election");
			numNodes = 4;
			numElections = 1;
		}
		nodes = new Node[numNodes];	// Create an array of NODES nodes
		try{
			for (int i = 0; i<numNodes; i++)
				nodes[i] = new Node(HOSTNAME, STARTPORT+i);		// Create array of nodes
			for (int i = 0; i<numNodes; i++)
				nodes[i].getPO().updateAddressBook();	// Fill address books
		}catch(PostalException e){
			System.err.println("Error creating nodes: "+e);
		}
	}
	
	/**
	 * Has a specified node start a new leader election.
	 * @param electingNode the node to start the election
	 */
	public void startElection(int electingNode){
		try{
			nodes[electingNode].startElection();
		}catch(PostalException e){
			System.err.println("Error in election: "+e);
		}
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("Start Election")){
			if (!electing){
				electing = true;
				for(int i=0; i<numElections; i++)
					new Thread(new ElectionStarter()).start();
				
			}
		}else if(e.getActionCommand().equals("Print Topology")){
			listLeaders();
		}else if(e.getActionCommand().equals("Join Network")){
			if (!created){
				created = true;
				createNodes();
			}
		}
	}

	public void listLeaders(){
		System.out.println("** TOTAL MESSAGES: "+numMessages+" **");
		System.out.println("\n=============== T O P O L O G Y ===============\n");
		for(int i=0; i<nodes.length; i++){
			System.out.println(nodes[i].getChildren());
			System.out.println(nodes[i].getParent());
			if(nodes[i].isLeader())
				System.out.println("Node "+nodes[i].getID()+" is the leader.");
		}
	}
	
	public static void main(String[] args){
		new LeaderElectionGUI();
	}
	
	/**
	 * Internal runnable class to start an election from a given node.
	 */
	class ElectionStarter implements Runnable{
		public void run(){
				nodeToStartElection = (nodeToStartElection+1)%numNodes;
				startElection(nodeToStartElection);
		}
	}
}
